/* Copyright 2017, 2018, Gabriel Czernikier
 *
 * This file is part of Notehaus.
 * Notehaus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * Notehaus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with Notehaus.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef __NOTEHAUS_TYPES
#define __NOTEHAUS_TYPES
#include <stdint.h>
#include <stdlib.h>
/* Some pieces of code are struct list_head and macros LIST_HEAD_INIT, LIST_HEAD, INIT_LIST_HEAD, list_entry, borrowed from Linux 2.4's include/linux/list.h file,
 * via the Linux Kernel 2.4 Internals book, from which specific section is 2.4, "Linux linked list implementation" (https://www.tldp.org/LDP/lki/lki-2.html#ss2.4)
 * Each case is pointed with a note side along the fragment of code it describes.
 * Rather than copied verbatim, the code could have been altered for the sake of fitness or any other purpose. Other portions of code are not copied but derived from that original ones.
 * Along with the fact the original software is under some form of a most mainstream free software license, you are advised to refer to that license for further details.
 */
struct list_head {  // From Linux 2.4 in include/linux/list.h
struct list_head *next, *prev;
};
// LIST_HEAD_INIT, LIST_HEAD, INIT_LIST_HEAD, list_entry, list_for_each from Linux 2.4 in include/linux/list.h
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = ptr; (ptr)->prev = ptr; \
} while (0)
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = (pos)->next)
#define list_for_each_entry(entry_ptr, type, member, head) \
for (entry_ptr = (head)->next!=(head) ? list_entry((head)->next, type, member) : NULL; (entry_ptr)!=NULL; entry_ptr = (entrt_ptr)->member.next!=(head) ? list_entry((entrt_ptr)->member.next, type, member) : NULL)
#define range_for_each(pos, first, last) \
for (pos = first; (pos) != (last); pos = (pos)->next)
#define range_for_each_entry(entry_ptr, type, member, first, last) \
for (entry_ptr = (first)!=(last) ? list_entry(first, type, member) : NULL; (entry_ptr)!=NULL; entry_ptr = (entrt_ptr)->member.next!=(last) ? list_entry((entrt_ptr)->member.next, type, member) : NULL)
#define list_peek_entry(type, member, head) \
(head)->next!=(head) ? list_entry((head)->next, type, member) : NULL;
#define list_peek_next_entry(entry_ptr, type, member, head) \
(entry_ptr)->member.next!=(head) ? list_entry((entry_ptr)->member.next, type, member) : NULL;
#define list_add(ptr, head) do { \
(ptr)->next = (head)->next; (head)->next = ptr; (ptr)->prev = head; (ptr)->next->prev = ptr; \
} while(0)
#define list_add_tail(ptr, head) do { \
(ptr)->prev = (head)->prev; (head)->prev = ptr; (ptr)->next = head; (ptr)->prev->next = ptr; \
} while(0)
#define list_del(ptr) do { \
(ptr)->next->prev = (ptr)->prev; (ptr)->prev->next = (ptr)->next; \
} while(0)
// Gets the first element from a list, removes it, and derreferences the original entry,
#define list_pop_entry(entry_ptr, head, type, member) do { \
	if((head)->next==(head)) { \
		entry_ptr = NULL; \
	} \
	else { \
		entry_ptr = list_entry((head)->next, type, member); \
		list_del((head)->next); \
	} \
} while(0)

struct size_data {
  size_t size;
  void *data;
  struct list_head size_data_list;
  void(*data_pack_fnc)(void *(*write_fnc)(void *src, size_t n), struct size_data *for_pack);
};
struct size_data *for_ubyte_array(struct size_data **sd, size_t n);
struct size_data *for_uint16_t(struct size_data **sd);
struct size_data *for_uint32_t(struct size_data **sd);
struct size_data *for_lengthed_wide_sequence(struct size_data **sd, size_t n);
struct size_data *for_generic_ptr(struct size_data **sd);
int lengthed_wide_sequence_compar_adapt(const void *s1, const void *s2);
#endif
